"""高阶函数"""
# abs(-10)是函数调用，而abs是函数本身。
from functools import reduce

print(abs(-10))
print(abs)

# 要获得函数调用结果，我们可以把结果赋值给变量：
x = abs(-10)
# 但是，如果把函数本身赋值给变量呢？
f = abs
# 结论：函数本身也可以赋值给变量，即：变量可以指向函数。
print(f)
print(f(-10)) # # 成功！说明变量f现在已经指向了abs函数本身。直接调用abs()函数和调用变量f()完全相同。
""" 既然变量可以指向函数，函数的参数能接收变量，那么一个函数就可以接收另一个函数作为参数，这种函数就称之为高阶函 """

def add(x, y, f):
    return f(x) + f(y)
x = -5
y = 6
f = abs
print(add(x, y, f))
print(add(-5, -6, abs))

# Python内建了map()和reduce()函数。
# map()函数接收两个参数，一个是函数，一个是Iterable，map将传入的函数依次作用到序列的每个元素，并把结果作为新的Iterator返回。
def f(x):
    return x*x
r = map(f, [1, 2, 3, 4, 5])
print(list(r))
# reduce把一个函数作用在一个序列[x1, x2, x3, ...]上，这个函数必须接收两个参数，reduce把结果继续和序列的下一个元素做累积计算
def add(x, y):
    return x + y
r = reduce(add, [1,3,5,7,9])
print(r)

# 如果考虑到字符串str也是一个序列，对上面的例子稍加改动，配合map()，我们就可以写出把str转换为int的函数：
def fn(x, y):
    return x * 10 + y
def char2num(s):
    return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
print(reduce(fn, map(char2num, '13579')))

# 整理成一个str2int的函数就是：
def str2int(s):
    def fn(x, y):
        return x * 10 + y
    def char2num(s):
        return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
    return reduce(fn, map(char2num, s))
print(str2int('13579'))

# 还可以用Lambda函数进一步简化成：
def char2num(s):
    return {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}[s]
def str2int(s):
    return reduce(lambda x, y: x * 10 + y, map(char2num, s))
print(str2int('13579'))

def up(name):
    return name.capitalize()
L = ['adam', 'LISA', 'barT']
print(list(map(up, L)))

# 和map()类似，filter()也接收一个函数和一个序列。和map()不同的时，filter()把传入的函数依次作用于每个元素，然后根据返回值是True还是False决定保留还是丢弃该元素。
def is_odd(n):
    return n % 2 == 1
print(list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])))

def not_empty(s):
    return s and s.strip()
print(list(filter(not_empty, ['A', 'B', 'C', None, 'E', '   '])))
# 用filter求素数
def _odd_iter():
    n = 1
    while True:
        n = n + 2
        yield n
def _not_divisible(n):
    return lambda x: x % n != 0
def primes():
    yield 2
    it = _odd_iter() # 初始序列
    while True:
        n = next(it) # 返回序列的第一个数
        yield n
        it = filter(_not_divisible(n), it) # 构造新序列

for n in primes():
    if n < 1000:
        print(n)
    else:
        break

# Python内置的sorted()函数就可以对list进行排序：
print(sorted([36, 5, -12, 9, -21]))
# sorted()函数也是一个高阶函数，它还可以接收一个key函数来实现自定义的排序，例如按绝对值大小排序
# key指定的函数将作用于list的每一个元素上，并根据key函数返回的结果进行排序。
print(sorted([36, 5, -12, 9, -21], key=abs))
# 这样，我们给sorted传入key函数，即可实现忽略大小写的排序：
print(sorted(['bob', 'about', 'Zoo', 'credit'], key=str.lower))
# 要进行反向排序，不必改动key函数，可以传入第三个参数reverse=True：
print(sorted(['bob', 'about', 'Zoo', 'credit'], key=str.lower, reverse=True))


L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

def by_name(t):
    return t[0]

L2 = sorted(L, key=by_name)
print(L2)


# 再按成绩从高到低排序：

# -*- coding: utf-8 -*-

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_score(t):
    return t[1]
L2 = sorted(L, key=by_score, reverse=True)
print(L2)